package com.jjh.util;

import com.jjh.consts.Properties;
import com.jjh.pojo.Dishes;
import com.jjh.wrapper.QueryBody;
import com.jjh.wrapper.QueryWrapper;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * 文件工具类
 * @author JJH
 */
public class FileUtils {

    /**
     * 根据文件路径将文件内容返回为集合
     * @param path 文件路径
     * @param clazz 要返回对象的类型
     * @return 对象集合
     */
 public static  List<Object> fileToList(String path, Class<?> clazz) {

      List<Object> list = new ArrayList<>();

      BufferedReader br = null;
      try {
          br = new BufferedReader(new FileReader(path));
          //读掉第一行数据(表头)
          br.readLine();
          String row;
          while ((row=br.readLine()) != null) {
              //先把对象创建出来
              Object obj = clazz.newInstance();
              //获取每一个元素
              String[] s = row.split(" ");
              //获取属性集合
              Field[] fields = clazz.getDeclaredFields();
              for (int i=0;i<fields.length;i++) {
                  //获取属性的类型
                  Class<?> type = fields[i].getType();
                  String name = fields[i].getName();
                String setXxx="set"+name.substring(0,1).toUpperCase()+name.substring(1);
                 //获取set方法
                  Method setMethod = clazz.getDeclaredMethod(setXxx,type);
                  //把参数类型转换一下
                  String s1 = s[i];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //调用set方法给属性赋值
                  setMethod.invoke(obj,arg);
              }
               //装入集合中
              list.add(obj);
          }
          return list;
      } catch (IOException | InvocationTargetException | NoSuchMethodException | InstantiationException |
               IllegalAccessException e) {
          throw new RuntimeException(e);
      } finally {
          try {
              assert br != null;
              br.close();
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }


  }

    /**
     * 将集合保存到文件中去
     * @param list 要保存的结合
     * @param path 文件路径
     * @param clazz 对象的类型
     * @return 是否保存成功
     * @param
     */
 public static  boolean ListToFile(List<Object> list, String path, Class<?> clazz){

      BufferedWriter bw = null;
      try {
          //第二个参数是允许追加写入
         bw = new BufferedWriter(new FileWriter(path,true));

          StringBuilder sb = new StringBuilder();
          for (Object obj : list) {

              //先获取对象的属性
              Field[] fields = clazz.getDeclaredFields();
              for (Field field : fields) {
                 //将第一个字母转化为大写
                  String name = field.getName();
                  String getXxx = "get"+name.substring(0, 1).toUpperCase()
                          + name.substring(1);
                 //调用get方法获取属性值
                  Method getMethod = clazz.getDeclaredMethod(getXxx);
                  String str = getMethod.invoke(obj).toString();
                  sb.append(str).append(" ");
              }
                sb.append("\n");
          }
             bw.write(sb.toString());

      } catch (Exception e) {
          throw new RuntimeException(e);
      } finally {
          try {
              assert bw != null;
              bw.close();
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }


      return true;
  }

    /**
     * 分案返回文件的行数
     * @param path 文件路径
     * @return 行数
     * @throws IOException
     */
  public static int getFileRow(String path) throws IOException {
     BufferedReader br = new BufferedReader(new FileReader(path));
     int sum =0;
     while (true){
         String str = br.readLine();
         if(str!=null){
             sum++;
         }else {
             break;
         }
     }
     return sum-1; //第一行不算
  }

    /**
     * 模拟分页查询
     * @param page 页数
     * @param size 尺寸
     * @param path 文件路径
     * @param clazz 返回集合中对象的类型
     * @return  对象集合
     */
  public static List<Object> pageList(int page,int size,String path, Class<?> clazz) {

      /*
          计算开始位置，第一行不算，所以是从第二行开始
          2-11为第一页了，
          12-22为第二页
          23-33为第三页
          start = 2 + (page-1)*size
          当我们最后一页不满的时候，如果要把这一页剩余的部分
          查出来，直接查询会报错误，我们需要判断最后一页还有多少
          余量，让我们最后一次循环次数等于这个余量，不要让它越界
       */

      List<Object> list = new ArrayList<>();
      try {
          //先获取总的条数,第一行不算
          int total = getFileRow(path) - 1;
          //计算一下最后一页有多少剩余(求余)
          int leastSize = total % size;

          BufferedReader br = new BufferedReader(new FileReader(path));
          //先让它读到start
          int start = 2 + (page - 1) * size;
          for (int i = 1; i < start; i++) {
              br.readLine();
          }
          //判断一下循环的次数，看看是满的，还是最后一页剩余的
          int num = total - (page-1) * size;
          int loop ; //循环次数
          if(leastSize==0||num>=10){
              loop = size;
          }else {
              loop = leastSize-1;
          }
          //然后让它读size次，默认为10
          for (int i = 0; i < loop; i++) {
              String row = br.readLine();
              //先把对象创建出来
              Object obj = clazz.newInstance();
              //获取每一个元素
              String[] s = row.split(" ");
              //获取属性集合
              Field[] fields = clazz.getDeclaredFields();
              for (int j = 0; j < fields.length; j++) {
                  //获取属性的类型
                  Class<?> type = fields[j].getType();
                  String name = fields[j].getName();
                  String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                  //获取set方法
                  Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                  //把参数类型转换一下
                  String s1 = s[j];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //调用set方法给属性赋值
                  setMethod.invoke(obj, arg);
              }
              //装入集合中
              list.add(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
      return list;
  }

    /**
     * 根据相等条件分页查询
     * @param page 页数
     * @param size 尺寸
     * @param path 文件路径
     * @param clazz 集合对象类型
     * @param wrapper 条件构造器
     * @return 对象集合
     */
  public static List<Object> pageQueryList(int page, int size, String path, Class<?> clazz, QueryWrapper wrapper){
         //把条件构造器中的条件拿出来
      List<QueryBody> querybodys = wrapper.getQueryArgs();


      List<Object> list = new ArrayList<>();
      List<Object> resList = new ArrayList<>();
      try {
          BufferedReader br = new BufferedReader(new FileReader(path));
          br.readLine(); // 先把第一行读了

          int rows = getFileRow(path);
          for(int i=0;i<rows-1;i++){
              String str = br.readLine();
              //先把对象创建出来
              Object obj = clazz.newInstance();
              //获取每一个元素
              String[] s = str.split(" ");
              //获取属性集合
              Field[] fields = clazz.getDeclaredFields();
              for (int j = 0; j < fields.length; j++) {
                  //获取属性的类型
                  Class<?> type = fields[j].getType();
                  String name = fields[j].getName();
                  String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                  //获取set方法
                  Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                  //把参数类型转换一下
                  String s1 = s[j];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //调用set方法给属性赋值
                  setMethod.invoke(obj, arg);
              }
              //装入集合中
              list.add(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
        // list.forEach(System.out::println);
      //以上是拿到了所有的元素，下面我们来对元素先进行一个筛选
      try {
          for (QueryBody querybody : querybodys) {
              //对每个条件进行过滤
              String key = querybody.getKey();
              String value = querybody.getValue();
              //每次先清空
              resList.removeAll(resList);
              for (Object obj:list) {
                      String getXxx = getXxx(key);
                      //调用get方法来获取属性值
                      Method getMethod = clazz.getDeclaredMethod(getXxx);
                      String res = getMethod.invoke(obj).toString();
                      //比对条件是否相等
                  if(res.equals(value)){
                      resList.add(obj);
                  }
              }

          }
      } catch (Exception e) {
          throw new RuntimeException(e);
      }
    // resList.forEach(System.out::println);
     // 如果不传page和size,默认就全查
      if(Objects.isNull(page)&&Objects.isNull(size)){
          return resList;
      }
      ArrayList<Object> pageList = new ArrayList<>();
      //分页查询
      /**
       * 0-9 第一页
       * 10-19 第二页
       * 20-21 第三页
       * 还是得先判断一下最后一页的剩余问题
       *
       */
      int start = (page-1)*size;
      for(int i = 0;i<resList.size();i++){
              if(i==start){


                  if(resList.size()<=size){
                      size = resList.size();
                  }else {
                      //多于一页，算一下余量
                      int mod = resList.size()%size;
                      if(mod>0){
                          //计算当前页面
                          int currentPage = start/size+1 ;
                          //算一下之前的总数据量是否
                          if(mod+(currentPage*size-1) < currentPage*size){
                              size = mod;
                          }
                      }
                  }

                  for(int j = start; j < (start+size); j++){
                      pageList.add(resList.get(j));
                      //pageList.forEach(System.out::println);
                  }
                  break;
              }
      }
     // pageList.forEach(System.out::println);
      return pageList;
  }

    /**
     * 分页查询的默认全查形式，方法重载
     * @param path 文件路径
     * @param clazz 对象类型
     * @param wrapper 条件构造器
     * @return  对象集合
     */
    public static List<Object> pageQueryList(String path, Class<?> clazz, QueryWrapper wrapper){
        //把条件构造器中的条件拿出来
        List<QueryBody> querybodys = wrapper.getQueryArgs();

        List<Object> list = new ArrayList<>();
        List<Object> resList = new ArrayList<>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(path));
            br.readLine(); // 先把第一行读了

            String row;
            while ((row=br.readLine())!=null){
                //先把对象创建出来
                Object obj = clazz.newInstance();
                //获取每一个元素
                String[] s = row.split(" ");
                //获取属性集合
                Field[] fields = clazz.getDeclaredFields();
                for (int j = 0; j < fields.length; j++) {
                    //获取属性的类型
                    Class<?> type = fields[j].getType();
                    String name = fields[j].getName();
                    String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                    //获取set方法
                    Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                    //把参数类型转换一下
                    String s1 = s[j];
                    Object arg = TypeUtils.getInstanceByType(s1, type);
                    //调用set方法给属性赋值
                    setMethod.invoke(obj, arg);
                }
                //装入集合中
                list.add(obj);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        //以上是拿到了所有的元素，下面我们来对元素先进行一个筛选
        try {
            for (QueryBody querybody : querybodys) {
                //对每个条件进行过滤
                String key = querybody.getKey();
                String value = querybody.getValue();
               // System.out.println(key+":"+value);
                //每次先清空
                resList.removeAll(resList);
                for (Object obj:list) {
                    String getXxx = getXxx(key);
                    //调用get方法来获取属性值
                    Method getMethod = clazz.getDeclaredMethod(getXxx);
                    Object res = getMethod.invoke(obj);
                    //比对条件是否相等
                    if(res.toString().equals(value)){
                        resList.add(obj);
                    }
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return resList;
    }

  private static String getXxx(String name){

     return "get" + name.substring(0,1).toUpperCase()
              + name.substring(1);

  }

    /**
     * 根据主键修改改行数据
     * @param
     * @param
     */
    public static boolean updateOne(String path, Object obj) {

        Class<?> aClass = obj.getClass();
        StringBuilder updateRow = new StringBuilder();
        Method getMethod = null;
        String str = null;
        String id = null;

        Field[] fields = aClass.getDeclaredFields();
        for (int i = 0;i<fields.length;i++) {
            try {
                getMethod = aClass.getDeclaredMethod(getXxx(fields[i].getName()));
                str = getMethod.invoke(obj).toString();
                updateRow.append(str).append(" ");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if(i==0){
                id = str;
            }
        }


        StringBuilder sb = new StringBuilder();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(path))));
            //先把表头添加上
            String head = reader.readLine();
            sb.append(head).append("\r\n");

            int rows = getFileRow(path);

            for (int i = 0; i <rows ; i++) {
                String row = reader.readLine();
                String Id = row.split(" ")[0];
                if(id.equals(Id)) {
                   sb.append(updateRow).append("\r\n");
                }else {
                    sb.append(row).append("\r\n");
                }
            }
            //再把文件写回去
            BufferedWriter writer = new BufferedWriter(new FileWriter(path));

            writer.write(sb.toString());

           reader.close();
           writer.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


         return true;

    }

}
